package org.xyq.singleton.lazy;

/**
 * @author xuyanqing
 * @description ⭐⭐3.单例模式-懒汉式-双重检查锁定（Double-Check Locking）【推荐使用】
 * <p>
 * 原理
 * 在进入同步块前先进行一次非同步检查，只有当实例为 null 时才进入同步块；在同步块内部再进行一次检查，确保只创建一次实例。
 * 注意：必须将实例声明为 volatile，防止由于指令重排序造成线程安全问题。
 * <p>
 * 深入分析
 * 为什么需要双重检查？
 * 第一次检查是为了避免每次都进入同步块，提高效率；第二次检查是为了防止多个线程在同步块内同时创建实例。
 * volatile 的作用
 * 在 Java 中，实例化对象（instance = new Singleton();）实际上可以分为以下几个步骤：
 * 1.分配内存空间；
 * 2.初始化对象；
 * 3.将内存地址赋值给 instance 变量。
 * 由于指令重排序，步骤 2 和 3 可能会调换，如果没有 volatile 修饰，另一个线程可能会看到一个未完全初始化的对象。
 * <p>
 * 优缺点
 * 优点：
 * 线程安全、实现延迟加载；
 * 同步代码块只在第一次初始化时执行，提高了效率。
 * 缺点：
 * 实现相对复杂，需要正确使用 volatile 和双重检查机制。
 * @date 2025-02-14 15:46
 * @creed where there is a will,there is a way. yx
 */

public class DoubleCheckLocking {

    // volatile 关键字确保多线程环境下变量的可见性和禁止指令重排序
    private volatile static DoubleCheckLocking instance;

    private DoubleCheckLocking() {
    }

    public static DoubleCheckLocking getInstance() {
        if (instance == null) { // 第一次检查（无锁）
            synchronized (DoubleCheckLocking.class) {
                if (instance == null) { // 第二次检查（有锁）
                    instance = new DoubleCheckLocking();
                }
            }
        }
        return instance;
    }
}
